"""
Health check endpoints for CodeMCP API.

Provides health monitoring, status checks, and system diagnostics.
"""

from typing import Dict, Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from datetime import datetime, timedelta
import asyncio

from ...core.error_handler import handle_error, log_info, log_warning
from ...core.config import Config
from ...core.monitoring import HealthMonitor, HealthStatus
from ...gateway.load_balancer import LoadBalancer
from ...gateway.session import SessionManager
from ..models.responses import (
    HealthResponse,
    StatisticsResponse,
    LoadBalancerResponse,
    BaseResponse
)

router = APIRouter(prefix="/health", tags=["health"])

# Dependencies
def get_config() -> Config:
    """Get configuration dependency."""
    return Config()

def get_health_monitor() -> HealthMonitor:
    """Get health monitor dependency."""
    pass

def get_load_balancer() -> LoadBalancer:
    """Get load balancer dependency."""
    pass

def get_session_manager() -> SessionManager:
    """Get session manager dependency."""
    pass


@router.get("/", response_model=HealthResponse)
async def get_health_status(
    include_details: bool = Query(False, description="Include detailed component health"),
    config: Config = Depends(get_config),
    health_monitor: HealthMonitor = Depends(get_health_monitor),
    load_balancer: LoadBalancer = Depends(get_load_balancer),
    session_manager: SessionManager = Depends(get_session_manager)
) -> HealthResponse:
    """
    Get overall system health status.
    
    Returns comprehensive health information including component status,
    system metrics, and performance indicators.
    """
    try:
        # Get overall health status
        health_data = await health_monitor.get_health_status()
        overall_status = HealthStatus(health_data["overall_status"])
        
        # Get system info
        system_info = {
            "cpu_usage": health_monitor.metrics.get_latest_metric("cpu_usage_percent"),
            "memory_usage": health_monitor.metrics.get_latest_metric("memory_usage_percent"),
            "disk_usage": health_monitor.metrics.get_latest_metric("disk_usage_percent")
        }
        
        # Convert metric points to values
        for key, metric_point in system_info.items():
            if metric_point:
                system_info[key] = metric_point.value
            else:
                system_info[key] = None
        
        # Get performance metrics
        performance_metrics = {
            "avg_response_time": health_monitor.metrics.get_metric_summary("response_time", 60),
            "requests_per_second": health_monitor.metrics.get_metric_summary("requests_per_second", 60),
            "error_rate": health_monitor.metrics.get_metric_summary("error_rate", 60)
        }
        
        # Get component health
        components = {}
        
        if include_details:
            # Database health
            components["database"] = await _check_database_health()
            
            # Cache health
            components["cache"] = await _check_cache_health()
            
            # MCP instances health
            components["mcp_instances"] = await _check_mcp_instances_health(load_balancer)
            
            # Session manager health
            components["session_manager"] = await _check_session_manager_health(session_manager)
        
        # Calculate uptime
        uptime_seconds = (datetime.utcnow() - health_monitor.metrics.start_time).total_seconds()
        
        return HealthResponse(
            health_status=overall_status,
            components=components,
            system_info=system_info,
            performance_metrics=performance_metrics,
            uptime_seconds=uptime_seconds
        )
        
    except Exception as e:
        error_response = handle_error(e, {"endpoint": "health_status"})
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/detailed", response_model=HealthResponse)
async def get_detailed_health(
    component: Optional[str] = Query(None, description="Specific component to check"),
    duration_minutes: int = Query(60, ge=1, le=1440, description="Metrics duration in minutes"),
    health_monitor: HealthMonitor = Depends(get_health_monitor),
    load_balancer: LoadBalancer = Depends(get_load_balancer),
    session_manager: SessionManager = Depends(get_session_manager)
) -> HealthResponse:
    """
    Get detailed health information for specific components.
    
    Provides in-depth health analysis with historical metrics.
    """
    try:
        components = {}
        
        if component is None or component == "all":
            # Check all components
            components["gateway"] = await _detailed_gateway_health(health_monitor, duration_minutes)
            components["database"] = await _detailed_database_health(duration_minutes)
            components["cache"] = await _detailed_cache_health(duration_minutes)
            components["mcp_instances"] = await _detailed_mcp_health(load_balancer, duration_minutes)
            components["sessions"] = await _detailed_session_health(session_manager, duration_minutes)
        else:
            # Check specific component
            if component == "gateway":
                components["gateway"] = await _detailed_gateway_health(health_monitor, duration_minutes)
            elif component == "database":
                components["database"] = await _detailed_database_health(duration_minutes)
            elif component == "cache":
                components["cache"] = await _detailed_cache_health(duration_minutes)
            elif component == "mcp_instances":
                components["mcp_instances"] = await _detailed_mcp_health(load_balancer, duration_minutes)
            elif component == "sessions":
                components["sessions"] = await _detailed_session_health(session_manager, duration_minutes)
            else:
                raise HTTPException(status_code=400, detail=f"Unknown component: {component}")
        
        # Determine overall status based on component health
        overall_status = _determine_overall_health(components)
        
        return HealthResponse(
            health_status=overall_status,
            components=components,
            system_info={},
            performance_metrics={},
            uptime_seconds=0.0
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "detailed_health",
            "component": component
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/statistics", response_model=StatisticsResponse)
async def get_health_statistics(
    period: str = Query("current", description="Statistics period (current, hourly, daily)"),
    component: Optional[str] = Query(None, description="Specific component statistics"),
    health_monitor: HealthMonitor = Depends(get_health_monitor),
    load_balancer: LoadBalancer = Depends(get_load_balancer)
) -> StatisticsResponse:
    """
    Get health and performance statistics.
    
    Returns aggregated statistics for the specified period and components.
    """
    try:
        statistics = {}
        
        if component is None or component == "all":
            # Get all statistics
            statistics["system"] = _get_system_statistics(health_monitor, period)
            statistics["gateway"] = _get_gateway_statistics(health_monitor, period)
            statistics["load_balancer"] = load_balancer.get_statistics()
            statistics["requests"] = _get_request_statistics(health_monitor, period)
            statistics["errors"] = _get_error_statistics(health_monitor, period)
        else:
            # Get specific component statistics
            if component == "system":
                statistics["system"] = _get_system_statistics(health_monitor, period)
            elif component == "gateway":
                statistics["gateway"] = _get_gateway_statistics(health_monitor, period)
            elif component == "load_balancer":
                statistics["load_balancer"] = load_balancer.get_statistics()
            elif component == "requests":
                statistics["requests"] = _get_request_statistics(health_monitor, period)
            elif component == "errors":
                statistics["errors"] = _get_error_statistics(health_monitor, period)
            else:
                raise HTTPException(status_code=400, detail=f"Unknown component: {component}")
        
        return StatisticsResponse(
            statistics=statistics,
            period=period,
            last_reset=health_monitor.metrics.start_time
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "health_statistics",
            "period": period,
            "component": component
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/load-balancer", response_model=LoadBalancerResponse)
async def get_load_balancer_health(
    include_instances: bool = Query(True, description="Include individual instance details"),
    load_balancer: LoadBalancer = Depends(get_load_balancer)
) -> LoadBalancerResponse:
    """
    Get load balancer health and statistics.
    
    Returns load balancer status, strategy, and instance information.
    """
    try:
        lb_stats = load_balancer.get_statistics()
        
        response_data = {
            "strategy": lb_stats["strategy"],
            "total_instances": lb_stats["total_instances"],
            "healthy_instances": lb_stats["healthy_instances"],
            "total_requests": lb_stats["total_requests"],
            "success_rate": lb_stats["success_rate"],
            "avg_response_time": lb_stats["avg_response_time"]
        }
        
        if include_instances:
            response_data["instances"] = lb_stats["instances"]
        else:
            response_data["instances"] = []
        
        return LoadBalancerResponse(**response_data)
        
    except Exception as e:
        error_response = handle_error(e, {"endpoint": "load_balancer_health"})
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/instances", response_model=Dict[str, Any])
async def get_mcp_instances_health(
    language: Optional[str] = Query(None, description="Filter by language"),
    status: Optional[str] = Query(None, description="Filter by status"),
    load_balancer: LoadBalancer = Depends(get_load_balancer)
) -> Dict[str, Any]:
    """
    Get health status of individual MCP instances.
    
    Returns detailed health information for each MCP instance.
    """
    try:
        instances = load_balancer.list_instances()
        
        # Apply filters
        if language:
            instances = [i for i in instances if i.language == language]
        
        if status:
            instances = [i for i in instances if i.status.value == status]
        
        # Get detailed health for each instance
        instance_health = []
        
        for instance in instances:
            health_data = {
                "id": instance.id,
                "url": instance.url,
                "language": instance.language,
                "status": instance.status.value,
                "health_score": instance.health_score,
                "current_connections": instance.current_connections,
                "max_connections": instance.max_connections,
                "total_requests": instance.total_requests,
                "failed_requests": instance.failed_requests,
                "success_rate": (1.0 - (instance.failed_requests / max(1, instance.total_requests))) * 100,
                "avg_response_time": instance.avg_response_time,
                "last_health_check": instance.last_health_check.isoformat() if instance.last_health_check else None,
                "last_error": instance.last_error,
                "consecutive_failures": instance.consecutive_failures
            }
            
            instance_health.append(health_data)
        
        return {
            "instances": instance_health,
            "total_count": len(instance_health),
            "languages": list(set(i["language"] for i in instance_health)),
            "statuses": list(set(i["status"] for i in instance_health))
        }
        
    except Exception as e:
        error_response = handle_error(e, {"endpoint": "mcp_instances_health"})
        raise HTTPException(status_code=500, detail=error_response)


@router.post("/reset-statistics", response_model=BaseResponse)
async def reset_health_statistics(
    component: Optional[str] = Query(None, description="Component to reset (all if not specified)"),
    health_monitor: HealthMonitor = Depends(get_health_monitor),
    load_balancer: LoadBalancer = Depends(get_load_balancer)
) -> BaseResponse:
    """
    Reset health statistics.
    
    Resets statistics for the specified component or all components.
    """
    try:
        if component is None or component == "all":
            # Reset all statistics
            health_monitor.metrics.metrics.clear()
            health_monitor.metrics.start_time = datetime.utcnow()
            load_balancer.reset_statistics()
            log_info("All health statistics reset")
        else:
            # Reset specific component
            if component == "health_monitor":
                health_monitor.metrics.metrics.clear()
                health_monitor.metrics.start_time = datetime.utcnow()
                log_info("Health monitor statistics reset")
            elif component == "load_balancer":
                load_balancer.reset_statistics()
                log_info("Load balancer statistics reset")
            else:
                raise HTTPException(status_code=400, detail=f"Unknown component: {component}")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "reset_statistics",
            "component": component
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/metrics/{metric_name}")
async def get_metric_history(
    metric_name: str,
    duration_minutes: int = Query(60, ge=1, le=1440, description="Duration in minutes"),
    health_monitor: HealthMonitor = Depends(get_health_monitor)
) -> Dict[str, Any]:
    """
    Get historical data for a specific metric.
    
    Returns time series data for the specified metric.
    """
    try:
        history = health_monitor.get_metrics_history(metric_name, duration_minutes)
        
        if not history:
            raise HTTPException(status_code=404, detail=f"Metric '{metric_name}' not found")
        
        # Calculate summary statistics
        values = [point["value"] for point in history]
        summary = {
            "count": len(values),
            "min": min(values) if values else 0,
            "max": max(values) if values else 0,
            "mean": sum(values) / len(values) if values else 0,
            "latest": values[-1] if values else 0
        }
        
        return {
            "metric_name": metric_name,
            "duration_minutes": duration_minutes,
            "data_points": history,
            "summary": summary
        }
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "metric_history",
            "metric_name": metric_name
        })
        raise HTTPException(status_code=500, detail=error_response)


# Helper functions

async def _check_database_health() -> Dict[str, Any]:
    """Check database health."""
    try:
        # This would check actual database connectivity
        return {
            "status": "healthy",
            "response_time": 0.05,
            "connections": {
                "active": 5,
                "idle": 10,
                "total": 15
            },
            "last_check": datetime.utcnow().isoformat()
        }
    except Exception as e:
        return {
            "status": "unhealthy",
            "error": str(e),
            "last_check": datetime.utcnow().isoformat()
        }


async def _check_cache_health() -> Dict[str, Any]:
    """Check cache health."""
    try:
        # This would check actual cache connectivity
        return {
            "status": "healthy",
            "hit_rate": 0.85,
            "memory_usage": 0.60,
            "connections": 20,
            "last_check": datetime.utcnow().isoformat()
        }
    except Exception as e:
        return {
            "status": "unhealthy",
            "error": str(e),
            "last_check": datetime.utcnow().isoformat()
        }


async def _check_mcp_instances_health(load_balancer: LoadBalancer) -> Dict[str, Any]:
    """Check MCP instances health."""
    try:
        instances = load_balancer.list_instances()
        healthy_count = len([i for i in instances if i.status.value == "healthy"])
        
        return {
            "status": "healthy" if healthy_count > 0 else "unhealthy",
            "total_instances": len(instances),
            "healthy_instances": healthy_count,
            "languages": list(set(i.language for i in instances)),
            "last_check": datetime.utcnow().isoformat()
        }
    except Exception as e:
        return {
            "status": "unhealthy",
            "error": str(e),
            "last_check": datetime.utcnow().isoformat()
        }


async def _check_session_manager_health(session_manager: SessionManager) -> Dict[str, Any]:
    """Check session manager health."""
    try:
        # This would check session manager status
        return {
            "status": "healthy",
            "active_sessions": 15,
            "total_sessions": 150,
            "memory_usage": 0.30,
            "last_check": datetime.utcnow().isoformat()
        }
    except Exception as e:
        return {
            "status": "unhealthy",
            "error": str(e),
            "last_check": datetime.utcnow().isoformat()
        }


async def _detailed_gateway_health(health_monitor: HealthMonitor, duration_minutes: int) -> Dict[str, Any]:
    """Get detailed gateway health."""
    return {
        "status": "healthy",
        "uptime": (datetime.utcnow() - health_monitor.metrics.start_time).total_seconds(),
        "response_times": health_monitor.get_metrics_history("response_time", duration_minutes),
        "request_rates": health_monitor.get_metrics_history("requests_per_second", duration_minutes),
        "error_rates": health_monitor.get_metrics_history("error_rate", duration_minutes)
    }


async def _detailed_database_health(duration_minutes: int) -> Dict[str, Any]:
    """Get detailed database health."""
    return {
        "status": "healthy",
        "connection_pool": {
            "active": 5,
            "idle": 10,
            "total": 15,
            "max": 50
        },
        "query_performance": {
            "avg_query_time": 0.05,
            "slow_queries": 0,
            "total_queries": 1000
        }
    }


async def _detailed_cache_health(duration_minutes: int) -> Dict[str, Any]:
    """Get detailed cache health."""
    return {
        "status": "healthy",
        "performance": {
            "hit_rate": 0.85,
            "miss_rate": 0.15,
            "eviction_rate": 0.02
        },
        "memory": {
            "used_mb": 512,
            "total_mb": 1024,
            "usage_percent": 50.0
        }
    }


async def _detailed_mcp_health(load_balancer: LoadBalancer, duration_minutes: int) -> Dict[str, Any]:
    """Get detailed MCP instances health."""
    stats = load_balancer.get_statistics()
    return {
        "status": "healthy" if stats["healthy_instances"] > 0 else "unhealthy",
        "instances": stats["instances"],
        "load_balancing": {
            "strategy": stats["strategy"],
            "total_requests": stats["total_requests"],
            "success_rate": stats["success_rate"],
            "avg_response_time": stats["avg_response_time"]
        }
    }


async def _detailed_session_health(session_manager: SessionManager, duration_minutes: int) -> Dict[str, Any]:
    """Get detailed session manager health."""
    return {
        "status": "healthy",
        "sessions": {
            "active": 15,
            "total": 150,
            "expired": 5
        },
        "memory_usage": {
            "sessions_mb": 50,
            "cache_mb": 100,
            "total_mb": 150
        }
    }


def _determine_overall_health(components: Dict[str, Any]) -> HealthStatus:
    """Determine overall health based on component health."""
    if not components:
        return HealthStatus.UNKNOWN
    
    statuses = [comp.get("status", "unknown") for comp in components.values()]
    
    if "unhealthy" in statuses:
        return HealthStatus.UNHEALTHY
    elif "warning" in statuses:
        return HealthStatus.WARNING
    elif all(status == "healthy" for status in statuses):
        return HealthStatus.HEALTHY
    else:
        return HealthStatus.UNKNOWN


def _get_system_statistics(health_monitor: HealthMonitor, period: str) -> Dict[str, Any]:
    """Get system statistics."""
    duration_minutes = {"current": 60, "hourly": 60, "daily": 1440}.get(period, 60)
    
    return {
        "cpu_usage": health_monitor.metrics.get_metric_summary("cpu_usage_percent", duration_minutes),
        "memory_usage": health_monitor.metrics.get_metric_summary("memory_usage_percent", duration_minutes),
        "disk_usage": health_monitor.metrics.get_metric_summary("disk_usage_percent", duration_minutes)
    }


def _get_gateway_statistics(health_monitor: HealthMonitor, period: str) -> Dict[str, Any]:
    """Get gateway statistics."""
    duration_minutes = {"current": 60, "hourly": 60, "daily": 1440}.get(period, 60)
    
    return {
        "response_time": health_monitor.metrics.get_metric_summary("response_time", duration_minutes),
        "requests_per_second": health_monitor.metrics.get_metric_summary("requests_per_second", duration_minutes),
        "uptime_hours": (datetime.utcnow() - health_monitor.metrics.start_time).total_seconds() / 3600
    }


def _get_request_statistics(health_monitor: HealthMonitor, period: str) -> Dict[str, Any]:
    """Get request statistics."""
    duration_minutes = {"current": 60, "hourly": 60, "daily": 1440}.get(period, 60)
    
    return {
        "total_requests": health_monitor.metrics.get_metric_summary("total_requests", duration_minutes),
        "successful_requests": health_monitor.metrics.get_metric_summary("successful_requests", duration_minutes),
        "failed_requests": health_monitor.metrics.get_metric_summary("failed_requests", duration_minutes)
    }


def _get_error_statistics(health_monitor: HealthMonitor, period: str) -> Dict[str, Any]:
    """Get error statistics."""
    duration_minutes = {"current": 60, "hourly": 60, "daily": 1440}.get(period, 60)
    
    return {
        "error_rate": health_monitor.metrics.get_metric_summary("error_rate", duration_minutes),
        "error_types": {},  # This would be populated from actual error tracking
        "recent_errors": []  # This would be populated from error logs
    }